﻿using HamcoWcs.Tools.Tibco.Entities;
using HamcoWcs.Tools.Tibco.MesMsgService;
using System;
using System.Runtime.Remoting.Contexts;
using System.Threading.Tasks;
using System.Xml;
using TIBCO.Rendezvous;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace HamcoWcs.Tools.Tibco
{
    public partial class TibcoTool : IDisposable
    {
        #region Constructor
        private TibcoConfiguration _config;
        public Action<string> OnReceiving { get; set; }
        public Action<string> OnSending { get; set; }
        public Action<string> OnErrorPrint { get; set; }
        public NetTransport NetTransport { get; set; }
        public Queue RecvQueue { get; set; }
        public Listener RecvListener { get; set; }

        private VirtualTibcoServer _virtualTibcoServer;

        private Context _context;

        public void SetContext(Context context)
        {
            _context = context;
            _context.TibcoTool = this;

            Task.Run(async () =>
            {
                while (true)
                {
                    MsgHandle(context);
                    await Task.Delay(100);
                }
            });

            Print("Tibco message handle service has started.");
        }


        private void MsgHandle(Context context)
        {
            var messages = context.Client.Queryable<MesMsgQueue>().OrderBy(x => x.TransactionId).ToList();

            if (messages.Count == 0) return;

            foreach (var message in messages)
            {
                IMesMsgParser parser = null;
                try
                {
                    parser = context.MesMsgParserFactory.GetParser(message.Status);
                    if (parser == null) continue;
                    parser.HandleEvent(message, context);
                }
                catch (Exception ex)
                {
                    message.Status = EnumMesMsgStatus.Error;
                    OnErrorPrint?.Invoke(ex.Message);
                }
                finally
                {
                    if (message != null && parser != null)
                        context.Client.Updateable(message).ExecuteCommand();
                }
            }
        }


        private void Print(string msg, string flag = "INFO", ConsoleColor consoleColor = ConsoleColor.White)
        {
            Console.ForegroundColor = consoleColor;
            Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.ffffff}] #[{flag,-6}] {msg}");
            Console.ForegroundColor = ConsoleColor.White;
        }


        private void PrintSqlConnectionString()
        {
            var str = Program.Configuration["ConnectionStrings:MysqlString"];

            var strs = str.Split(';');

            foreach (var item in strs)
            {
                if (string.IsNullOrEmpty(item) || item.Contains("pwd"))
                {
                    continue;
                }
                var a = item.Split('=');
                Print($"{a[0]} : {a[1]}");
            }


        }
        private void Init()
        {

            Print("TibcoServer is beginning!", consoleColor: ConsoleColor.Green);
            Print($"Current Configuration is '{TibcoConfigurationManager.Configuration.Environment}'", consoleColor: ConsoleColor.Blue);

            PrintSqlConnectionString();
            Console.WriteLine("".PadLeft(60, '='));
            Console.WriteLine($"Service:{TibcoConfigurationManager.Configuration.Service}");
            Console.WriteLine($"Network:{TibcoConfigurationManager.Configuration.Network}");
            Console.WriteLine($"Daemon:{TibcoConfigurationManager.Configuration.Daemon}");
            Console.WriteLine($"RecvSubject:{TibcoConfigurationManager.Configuration.RecvSubject}");
            Console.WriteLine($"SendSubject:{TibcoConfigurationManager.Configuration.SendSubject}");
            Console.WriteLine($"SendField:{TibcoConfigurationManager.Configuration.SendField}");
            Console.WriteLine($"SendTimeout:{TibcoConfigurationManager.Configuration.SendTimeout}");
            Console.WriteLine($"IsBuildWithVirtualTibcoServer:{TibcoConfigurationManager.Configuration.IsBuildWithVirtualTibcoServer}");
            if (_config.IsBuildWithVirtualTibcoServer)
                Console.WriteLine("Assembly Virtual TibcoServer");
            Console.WriteLine("".PadLeft(60, '='));

            Console.WriteLine($"\r\nIf you want to change other configuration,please shutdown this progress,then change the content in 'tibco.config.json'.\r\n");


            try
            {
                TIBCO.Rendezvous.Environment.Open();
                Print("Tibco Environment has open.");
            }
            catch (Exception)
            {
                throw new Exception("本地Tibco环境未找到");
            }

            try
            {
                this.NetTransport = new NetTransport(_config.Service, _config.Network, _config.Daemon);
                Print("Tibco NetTransport has created.");
            }
            catch (Exception)
            {
                throw new Exception("创建Transport失败");
            }

            this.RecvQueue = Queue.Default;
            Print("Tibco Queue has created.");
            //var dispatcher = new Dispatcher(RecvQueue);
            //Print("Tibco Dispatcher has created.");
            this.RecvListener = new Listener(RecvQueue, ReceiveHandler, NetTransport, _config.RecvSubject, null);
            Print("Tibco Listener has created.");

            if (_config.IsBuildWithVirtualTibcoServer)
            {
                _virtualTibcoServer = new VirtualTibcoServer(_config, NetTransport);
                Print("BuildWithVirtualTibcoServer");

            }

            Task.Run(async () =>
            {

                while (true)
                {
                    RecvQueue.Dispatch();
                    await Task.Delay(100);
                }
            });
            Print("Tibco receive service has started.");
            Print("Tibco init completed.");
        }


        public TibcoTool()
        {
            _config = TibcoConfigurationManager.Configuration;
            Init();
        }

        public TibcoTool(Action<string> OnSending, Action<string> OnReceiving, Action<string> OnErrorPrint) : this()
        {
            // 绑定打印事件
            this.OnSending += OnSending;
            this.OnReceiving += OnReceiving;
            this.OnErrorPrint += OnErrorPrint;
            Print($"Event OnSending    bind status:{(this.OnSending == null ? "failure" : "success")}.");
            Print($"Event OnReceiving  bind status:{(this.OnSending == null ? "failure" : "success")}.");
            Print($"Event OnErrorPrint bind status:{(this.OnSending == null ? "failure" : "success")}.");
        }

        public TibcoTool(Action<string> OnSending, Action<string> OnReceiving, Action<string> OnErrorPrint, Context context) : this(OnSending, OnReceiving, OnErrorPrint)
        {
            this.SetContext(context);
        }

        #endregion

        public bool GetIVirtualTibcoServerState()
        => _config.IsBuildWithVirtualTibcoServer;


        /// <summary>发送请求</summary>
        public string SendRequest(string content, string subject)
        {
            var message = new Message() { SendSubject = subject };
            message.AddField(_config.SendField, content);
            OnSending?.Invoke(content);
            string resContent = "";

            try
            {
                var res = this.NetTransport.SendRequest(message, _config.SendTimeout);

                if (res == null) throw new Exception(subject + "timeout");
                resContent = res.GetField(_config.SendField)?.Value.ToString() ?? "";
                if (string.IsNullOrEmpty(resContent)) throw new Exception("reply is null");
            }
            catch (Exception)
            {
                throw;
            }
            return resContent;
        }

        /// <summary>上报消息</summary>
        public void Send(string content, string subject)
        {
            try
            {
                LogAll(content);
            }
            catch (Exception)
            {

            }
            var message = new Message() { SendSubject = subject };
            message.AddField(_config.SendField, content);
            OnSending?.Invoke(content);

            this.NetTransport.Send(message);
        }

        private void SendVirtualReply(string message)
        {
            var replySubject = XmlHelper.GetReplySubject(message);
            var content = XmlHelper.SetReplyMessageName(message);

            var sendmessage = new Message() { SendSubject = replySubject };
            sendmessage.AddField(_config.SendField, content);
            this.NetTransport.Send(sendmessage);
        }

        /// <summary>回应Request</summary>
        public string SendReply(Message request, object tibcomsg)
        {
            var replyMessage = new Message();
            var xmlData = XmlHelper.Serialize(tibcomsg);
            replyMessage.AddField(_config.SendField, xmlData);
            OnSending?.Invoke(xmlData);
            this.NetTransport.SendReply(replyMessage, request);

            return xmlData;
        }

        #region IDisposable



        ~TibcoTool()
        {
            Dispose();
        }
        public void Dispose()
        {

            try
            {
                this.NetTransport.Destroy();
            }
            catch (Exception)
            {

            }

            try
            {
                this.RecvQueue.Destroy();
            }
            catch (Exception)
            {

            }

            try
            {
                this.RecvListener.Destroy();
            }
            catch (Exception)
            {

            }


            try
            {
                TIBCO.Rendezvous.Environment.Close();
            }
            catch (Exception)
            {

            }
            finally
            {
                GC.Collect();
            }


        }

        #endregion

    }
}
